package com.gitee.jnxj.nraft.election;

import com.gitee.jnxj.nraft.common.core.*;
import com.gitee.jnxj.nraft.common.log.LogEntry;
import com.gitee.jnxj.nraft.logreply.LogManager;
import com.gitee.jnxj.nrpc.spring.boot.autoconfigure.annotation.NRpcServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.example.nrpc.common.listener.RpcCompletableFuture;

import java.util.List;

/**
 * @author 江南小俊
 * @since 2021/7/13
 **/
@NRpcServiceImpl(RaftService.class)
@Slf4j
public class RaftServiceImpl implements RaftService {

    /**
     * 处理选举请求<br/>
     *
     * @param voteParam
     * @return java.util.concurrent.Future<java.lang.Boolean>
     * @author Jim
     * @since 2021/7/13 上午9:57
     **/

    @Override
    public synchronized RpcCompletableFuture<Boolean> requestVote(VoteReq voteParam) {
        Election election = Election.getInstance();
        Node node = election.getNode();
        if (node.getCurrentTerm() > voteParam.getTerm()) {
            //不接受任期比当前任期小的
            log.info("不接受任期比当前任期小的:{}", voteParam);
            return RpcCompletableFuture.completedFuture(false);
        } else if (node.getCurrentTerm() == voteParam.getTerm() && node.getVotedFor() != null) {
            log.info("该任期已同意别的候选者：{}", voteParam);
            return RpcCompletableFuture.completedFuture(false);
        } else {
            if (voteParam.getCommitIndex() < node.getCommitIndex()) {
                log.info("日志不完整，不同意：{}", voteParam);
                return RpcCompletableFuture.completedFuture(false);
            }
            log.info("同意选举：{}", voteParam);
            node.setVotedFor(voteParam.getCandidateId());
            node.setCurrentTerm(voteParam.getTerm());
            election.resetElectionTask();
            return RpcCompletableFuture.completedFuture(true);
        }
    }

    /**
     * 处理心跳请求
     *
     * @param heartbeatParam
     * @return org.example.nrpc.common.listener.RpcCompletableFuture<java.lang.Boolean>
     * @author Jim
     * @since 2021/7/13 上午11:40
     **/

    @Override
    public RpcCompletableFuture<HeartbeatResp> heartbeat(HeartbeatReq heartbeatParam) {
        Election election = Election.getInstance();
        Node node = election.getNode();
        if (node.getCurrentTerm() <= heartbeatParam.getTerm()) {
            log.info("接受Leader心跳，继续维护");
            election.resetElectionTask();
            node.setType(Node.NodeType.FOLLOWER);
            node.setVotedFor(heartbeatParam.getIndex());
            node.setCurrentTerm(heartbeatParam.getTerm());
            return RpcCompletableFuture.completedFuture(HeartbeatResp.builder().agree(true).build());
        } else {
            log.info("任期比自己的小，不承认Leader");
            return RpcCompletableFuture.completedFuture(HeartbeatResp.builder().agree(false).term(node.getCurrentTerm()).build());
        }
    }

    /**
     * AppendEntries RPC，同时leader发起，用来复制日志条目或者发送心跳
     *
     * @param appendEntriesReq
     * @return org.example.nrpc.common.listener.RpcCompletableFuture<com.gitee.jnxj.nraft.common.core.AppendEntriesResp>
     * @author Jim
     * @since 2021/7/14 下午4:34
     **/

    @Override
    public RpcCompletableFuture<AppendEntriesResp> appendEntries(AppendEntriesReq appendEntriesReq) {
        Election election = Election.getInstance();
        Node node = election.getNode();
        //如果参数term小于接收者的currentTerm，返回false
        if (appendEntriesReq.getTerm() < node.getCurrentTerm()) {
            return RpcCompletableFuture.completedFuture(AppendEntriesResp.builder().success(false).term(node.getCurrentTerm()).build());
        }//如果参数的term和prevLogTerm相等的的日志中不包含prevLogIndex的条目，返回false
        if (!checkLog(appendEntriesReq)) {
            return RpcCompletableFuture.completedFuture(AppendEntriesResp.builder().success(false).term(node.getCurrentTerm()).build());
        }
        updateLogEntries(appendEntriesReq.getEntries());
        //如果leaderCommit>commitIndex，设置commitIndex=min(leaderCommit, 上一个新条目的索引)
        if (appendEntriesReq.getLeaderCommit() > node.getCommitIndex()) {
            node.setCommitIndex(Math.min(appendEntriesReq.getLeaderCommit(), checkLastLogIndex()));
        }
        return RpcCompletableFuture.completedFuture(AppendEntriesResp.builder().success(true).term(node.getCurrentTerm()).build());
    }

    private void updateLogEntries(List<LogEntry> entries) {
        LogManager logManager = LogManager.getInstance();
        //现有条目与新条目（索引相同但任期不同）发生冲突，删除当前及以后的所有条目
        //添加不在日志中的新条目
        for (LogEntry entry : entries) {
            logManager.addEntry(entry);
        }

    }

    private long checkLastLogIndex() {
        return 0;
    }

    private boolean checkLog(AppendEntriesReq appendEntriesReq) {
        LogManager logManager = LogManager.getInstance();
        LogEntry logEntry = logManager.getEntryByKey(LogEntry.LogKey.builder()
                .keyId(appendEntriesReq.getPrevLogIndex())
                .build());
        if (logEntry == null) return false;
        return true;
    }


}
